<template>
    <bk-select v-bind="dropdownConf"
        :name="name"
        :loading="isLoading"
        :placeholder="isLoading ? $t('editPage.loadingData') : placeholder"
        :value="value"
        :disabled="disabled || isLoading"
        @edit="edit"
        @selected="handleSelect"
        @toggle="toggleVisible"
        @clear="handleClear"
        :popover-options="popoverOptions"
    >
        <bk-option
            v-for="item in list"
            :key="item.id"
            :id="item.id"
            :name="item.name"
        >
        </bk-option>
        <template v-if="mergedOptionsConf.hasAddItem">
            <div slot="extension" class="bk-selector-create-item">
                <a :href="addItemUrl" target="_blank">
                    <i class="devops-icon icon-plus-circle" />
                    {{ mergedOptionsConf.itemText }}
                </a>
            </div>
        </template>
    </bk-select>
</template>

<script>
    import mixins from '../mixins'
    export default {
        mixins: [mixins],
        props: {
            placeholder: {
                type: String
            },
            options: {
                type: Array,
                default: []
            },
            optionsConf: {
                type: Object,
                default: () => ({})
            }
        },
        data () {
            return {
                isLoading: false,
                list: this.options,
                webUrl: WEB_URL_PIRFIX
            }
        },
        computed: {
            popoverOptions () {
                return {
                    popperOptions: {
                        modifiers: {
                            preventOverflow: {
                                boundariesElement: 'window'
                            }
                        }
                    }
                }
            },
            projectId () {
                return this.$route.params.projectId
            },
            mergedOptionsConf () {
                return Object.assign({}, {
                    hasAddItem: false,
                    itemText: this.$t('template.relatedCodelib'),
                    itemTargetUrl: `/codelib/{projectId}/`,
                    url: '',
                    paramId: 'id',
                    paramName: 'name',
                    searchable: false,
                    clearable: false,
                    multiple: false
                }, this.optionsConf)
            },
            hasUrl () {
                return this.mergedOptionsConf && this.mergedOptionsConf.url && typeof this.mergedOptionsConf.url === 'string'
            },
            urlParamKeys () {
                if (this.hasUrl) {
                    const paramKey = this.mergedOptionsConf.url.match(/\{(.*?)\}/g)
                    return paramKey ? paramKey.map(key => key.replace(/\{(.*?)\}/, '$1')) : []
                }
                return []
            },
            queryParams () {
                const { atomValue = {}, $route: { params = {} } } = this
                return {
                    ...params,
                    ...atomValue
                }
            },
            isLackParam () {
                return this.urlParamKeys.some(key => {
                    return this.queryParams.hasOwnProperty(key) && (typeof this.queryParams[key] === 'undefined' || this.queryParams[key] === null || this.queryParams[key] === '')
                })
            },
            dropdownConf () {
                const { searchable, tools, multiple, clearable } = this.mergedOptionsConf
                return {
                    tools,
                    searchable,
                    multiple,
                    clearable
                }
            },
            addItemUrl () {
                const { webUrl, urlParse, mergedOptionsConf: { itemTargetUrl }, $route: { params } } = this
                const originUrl = /^(http|https):\/\//.test(itemTargetUrl) ? itemTargetUrl : webUrl + itemTargetUrl

                return urlParse(originUrl, params)
            }
        },
        watch: {
            options (newOptions) {
                this.list = newOptions
            },
            queryParams (newQueryParams, oldQueryParams) {
                if (this.urlParamKeys.some(key => newQueryParams[key] !== oldQueryParams[key])) {
                    this.handleClear()
                }
            }
        },
        created () {
            if (this.hasUrl) {
                this.freshList()
            }
        },
        methods: {
            handleSelect (selected, data) {
                this.handleChange(this.name, selected)
            },
            handleClear () {
                const val = this.dropdownConf.multiple ? [] : ''

                this.handleChange(this.name, val)
            },
            edit (index) {
                const hashId = this.list[index].repositoryHashId || ''
                const type = this.list[index].type || ''
                const groupId = this.list[index].groupHashId || ''
                if (hashId) {
                    const href = `${WEB_URL_PIRFIX}/codelib/${this.projectId}/${hashId}/${type}`
                    window.open(href, '_blank')
                } else if (groupId) {
                    const groupHref = `${WEB_URL_PIRFIX}/experience/${this.projectId}/setting/?groupId=${groupId}`
                    window.open(groupHref, '_blank')
                }
            },
            toggleVisible (open) {
                open && this.hasUrl && this.freshList()
            },
            urlParse (originUrl, query) {
                /* eslint-disable */
                return new Function('ctx', `return '${originUrl.replace(/\{(.*?)\}/g, '\'\+ ctx.$1 \+\'')}'`)(query)
                /* eslint-enable */
            },
            getUrlParamKey (url) {
                if (this.hasUrl) {
                    const paramKey = url.match(/\{(.*?)\}/g)
                    return paramKey || []
                }
                return []
            },
            transformList (res) {
                const list = this.getResponseData(res, this.mergedOptionsConf.dataPath)
                return list.map(item => {
                    if (typeof item === 'string') {
                        return {
                            id: item,
                            name: item
                        }
                    }
                    return {
                        ...item,
                        id: item[this.mergedOptionsConf.paramId],
                        name: item[this.mergedOptionsConf.paramName]
                    }
                })
            },
            async freshList () {
                if (this.isLackParam) { // 缺少参数时，选择列表置空
                    this.list = []
                    return
                }
                try {
                    const { atomValue = {}, transformList, $route: { params = {} }, mergedOptionsConf } = this
                    const changeUrl = this.urlParse(mergedOptionsConf.url, {
                        ...params,
                        ...atomValue
                    })
                    this.isLoading = true

                    const res = await this.$ajax.get(changeUrl)

                    this.list = transformList(res)
                    // 添加无权限查看项
                    const valueArray = mergedOptionsConf.multiple && Array.isArray(this.value) ? this.value : [this.value]
                    const listMap = this.list.reduce((listMap, item) => {
                        listMap[item.id] = item
                        return listMap
                    }, {})

                    valueArray.map(value => {
                        if (typeof value !== 'undefined' && value !== '' && !listMap[value]) {
                            this.list.splice(0, 0, {
                                id: value,
                                name: `******（${this.$t('editPage.noPermToView')}）`
                            })
                        }
                    })

                    this.$emit('change', this.list)
                } catch (e) {
                    this.$showTips({
                        message: e.message,
                        theme: 'error'
                    })
                } finally {
                    this.isLoading = false
                }
            }
        }
    }
</script>

<style lang="scss">
    .bk-form .bk-form-content,
    .form-field.bk-form-item {
        position: static;
    }
</style>
